Ruby的可靠性並非偶然;它是一種 有系統的紀律 建立在「早期測試、經常測試」理念之上。透過在撰寫功能程式碼的同時編寫單元測試,我們能將除錯從令人挫敗的 考古挖掘 轉化為精確且即時的邏輯驗證。
1. 單元測試的哲學
使用 Test::Unit 框架,我們將邏輯包裝在一個 Test::Unit::TestCase之中。以 test_ 開頭的方法可視為獨立的實驗室,其中個別程式碼單元會被檢測、探查與驗證。
2. 斷言的機制
斷言是程式碼中的邏輯閘。 assert_equal(預期值, 真實值) 將你的意圖與實際結果進行比較。若二者不符,測試就會失敗,並提供明確指引,指出需要修復的具體程式行。
3. 可擴展性的命名規則
一致性至關重要。單獨的測試檔案使用 tc_ (測試案例)前綴,而集合或套件則使用 ts_ (測試套件)前綴,確保隨著程式碼庫擴增,仍能保持良好的可導航性。
main.py
TERMINALbash — 80x24
> Ready. Click "Run" to execute.
>
QUESTION 1
In the
Test::Unit framework, which naming convention is required for a method to be automatically executed as a test?The method must end with
_test.The method must be named
verify_logic.The method must start with
test_.The method must be inside a
setup block.✅ Correct!
Correct! Ruby's test runner looks for methods starting with 'test_' to identify test cases.❌ Incorrect
The test runner specifically identifies methods starting with the prefix 'test_'.QUESTION 2
What is the primary difference between a file named
tc_orders.rb and ts_app.rb?tc_ is for C++ code; ts_ is for Ruby.tc_ represents an individual Test Case; ts_ represents a Test Suite (collection).tc_ is used for local tests; ts_ is for server tests.There is no functional difference; it is purely aesthetic.
✅ Correct!
Exactly. 'tc' stands for Test Case, while 'ts' stands for Test Suite, which usually requires multiple test cases.❌ Incorrect
The prefix 'tc' is for individual files containing test cases, while 'ts' is for suites that group those files together.QUESTION 3
Why does
assert_equal take two arguments?To compare the 'expected' value with the 'actual' result.
To define the minimum and maximum execution time.
To specify the class name and the method name.
To allocate memory for the test results.
✅ Correct!
Yes. It uses both to provide detailed error messages (e.g., 'Expected A, but got B').❌ Incorrect
Assertions compare your intended outcome (expected) against the code's output (actual).QUESTION 4
What happens if a test fails in the middle of a suite?
The entire computer restarts.
Ruby skips the rest of the file and deletes the log.
The test runner reports the failure and continues to the next test method.
The Ruby interpreter enters an infinite loop.
✅ Correct!
Test runners are designed to report failures while still attempting to run all other tests for maximum visibility.❌ Incorrect
Failures are reported as they happen, but the runner continues to execute remaining tests.QUESTION 5
Which Ruby library must be required to use
Test::Unit::TestCase?require 'debug'require 'test/unit'require 'benchmark'require 'roman'✅ Correct!
Correct. test/unit is the standard library for unit testing in the Pragmatic Programmer's era of Ruby.❌ Incorrect
You must require 'test/unit' to access the TestCase class and assertion methods.Case Study: The 'Archaeology' of Fred's Bug
Applying Unit Testing Principles to Legacy Code
Fred is working on a complex financial system. He spends three days writing a large feature, only to find a bug on day four. He now has to search through 2,000 lines of code to find the error, a process he calls 'code archaeology.'
Q
1. If Fred had unit tested his code as he wrote it, what two specific benefits would he have gained regarding bug detection?
Solution:
First, the unit test would have caught the logic error immediately while the implementation was fresh in his mind. Second, since the test would have targeted only the handful of lines he had just written, he would have identified the bug instantly without having to search through the entire 2,000-line codebase.
First, the unit test would have caught the logic error immediately while the implementation was fresh in his mind. Second, since the test would have targeted only the handful of lines he had just written, he would have identified the bug instantly without having to search through the entire 2,000-line codebase.
Q
2. In the Roman numeral example provided, the second assertion failed. What does the error message tell the developer about the code's behavior?
Solution:
The error message identifies that the assertion expected 'ix' but the code actually returned 'iiiiiiiii'. This reveals that the logic is currently only capable of handling unit increments ('i') and fails to implement the subtraction or grouping logic required for symbols like 'x' or 'v'.
The error message identifies that the assertion expected 'ix' but the code actually returned 'iiiiiiiii'. This reveals that the logic is currently only capable of handling unit increments ('i') and fails to implement the subtraction or grouping logic required for symbols like 'x' or 'v'.